/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package tmiranda.afd;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.Vector;
import sage.SageTVEventListener;
import sagex.api.*;

/**
 *
 * @author Tom Miranda
 */
public class Plugin implements sage.SageTVPlugin, SageTVEventListener {
   
    private final String                VERSION = "0.02";
    private sage.SageTVPluginRegistry   registry;
    private sage.SageTVEventListener    listener;
    
    public Plugin(sage.SageTVPluginRegistry Registry) {
        registry = Registry;
        listener = this;
    }

    public Plugin(sage.SageTVPluginRegistry Registry, boolean Reset) {
        registry = Registry;
        listener = this;
        if (Reset && !Global.IsClient())
            resetConfig();
    }
    
    // This method is called when the plugin should startup.
    @Override
    public void start() {
        System.out.println("AFD: Plugin: Starting. Version = " + VERSION);

        // Set the loglevel to what's in the .properties file.
        Integer DefaultLevel = Log.LOGLEVEL_WARN;
        String CurrentLevel = Configuration.GetServerProperty("afd/loglevel", DefaultLevel.toString());
        Integer SetLevel = Integer.decode(CurrentLevel);
        Log.SetLogLevel(SetLevel);  
        
        switch (Log.GetLogLevel()) {
            case Log.LOGLEVEL_MAX:      System.out.println("AFD: Plugin: LogLevel = Maximum."); break;
            case Log.LOGLEVEL_ERROR:    System.out.println("AFD: Plugin: LogLevel = Error."); break;
            case Log.LOGLEVEL_NONE:     System.out.println("AFD: Plugin: LogLevel = None."); break;
            case Log.LOGLEVEL_TRACE:    System.out.println("AFD: Plugin: LogLevel = Trace."); break;
            case Log.LOGLEVEL_VERBOSE:  System.out.println("AFD: Plugin: LogLevel = Verbose."); break;
            case Log.LOGLEVEL_WARN:     System.out.println("AFD: Plugin: LogLevel = Warn."); break;
            default:                    System.out.println("AFD: Plugin: Error.  Unknown LogLevel."); break;
        }
             
        // If we're running on a client we are done.
        if (Global.IsClient()) {
            Log.getInstance().write(Log.LOGLEVEL_WARN, "start: Running in Client mode.");
            return;
        }
        
        // Mark all future Airings of all ant-Favorites as Watched and DontLike to make sure they are not recorded.
        markFutureAirings();
        
        // Subscribe to what we need.
        Log.getInstance().write(Log.LOGLEVEL_TRACE, "start: Subscribing to events.");
        registry.eventSubscribe(listener, "EPGUpdateCompleted");
    }
    
    // This method is called when the plugin should shutdown.
    @Override
    public void stop() {
        Log.getInstance().write(Log.LOGLEVEL_TRACE, "Plugin: Stop received from Plugin Manager.");

        if (Global.IsClient()) {
            Log.getInstance().write(Log.LOGLEVEL_WARN, "stop: Running in Client mode.");
            return;
        }

        registry.eventUnsubscribe(listener, "EPGUpdateCompleted");
    }   
    
    // This method is called after plugin shutdown to free any resources
    // used by the plugin.
    @Override
    public void destroy() {
        if (Global.IsClient()) {
            Log.getInstance().write(Log.LOGLEVEL_WARN, "destroy: Running in Client mode.");
            Log.destroy();
            return;
        }

        Log.getInstance().write(Log.LOGLEVEL_TRACE, "destroy: Destroy received from Plugin Manager.");
        Log.destroy();
        registry = null;
        listener = null;
    }    
    
    // Returns the names of the settings for this plugin.
    @Override
    public String[] getConfigSettings() {
        return null;
    }
    
    // Returns the current value of the specified setting for this plugin.
    @Override
    public String getConfigValue(String setting) {
        return null;
    }
    
    // Returns the current value of the specified multichoice setting for
    // this plugin.
    @Override
    public String[] getConfigValues(String setting) {
        return null;
    }
    
    // Returns one of the constants above that indicates what type of value
    // is used for a specific settings.
    @Override
    public int getConfigType(String setting) {
        return 0;
    }
    
    // Sets a configuration value for this plugin.
    @Override
    public void setConfigValue(String setting, String value) {
        return;
    }
    
    // Sets a configuration values for this plugin for a multiselect choice.
    @Override
    public void setConfigValues(String setting, String[] values) {
        return;
    }
    
    // For CONFIG_CHOICE settings; this returns the list of choices.
    @Override
    public String[] getConfigOptions(String setting) {
        return null;
    }
    
    // Returns the label used to present this setting to the user.
    @Override
    public String getConfigLabel(String setting) {
        return null;
    }    
    
    // Returns the help text for a configuration setting.
    @Override
    public String getConfigHelpText(String setting) {
        return null;
    }
    
    // Resets the configuration of this plugin.
    @Override
    public final void resetConfig() {
        Log.getInstance().write(Log.LOGLEVEL_TRACE, "resetConfig: resetConfig received from Plugin Manager.");
        Log.SetLogLevel(Log.LOGLEVEL_WARN);
    }
    
    @Override
    public synchronized void sageEvent(String eventName, java.util.Map eventVars) {

        Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: event received = " + eventName);

        // Check that we have the right event.
        if (!eventName.startsWith("EPGUpdateCompleted")) {
            Log.getInstance().write(Log.LOGLEVEL_WARN, "sageEvent: Unexpected event received = " + eventName);
            return;
        }
        
        // Mark all future Airings of all ant-Favorites as Watched and DontLike to make sure they are not recorded.
        markFutureAirings();        
        
        Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Done.");
        return;
    }
    
    static void markFutureAirings() {
        
        Log.getInstance().write(Log.LOGLEVEL_TRACE, "markFutureAirings: Scanning database for anti-favorites.");
        
        ArrayList<Object> futureAirings = getFutureAirings();

        for (Object airing : futureAirings) {
            AntiFavorite af = new AntiFavorite(airing);
            
            if (af.isAntiFavorite()) {
                Log.getInstance().write(Log.LOGLEVEL_TRACE, "markFutureAirings: Possibly setting Watched and DontLike for future anti-Favorite " + ShowAPI.GetShowTitle(airing) + " " + ShowAPI.GetShowEpisode(airing));
                
                if (af.isMarkDontLike()) {
                    Log.getInstance().write(Log.LOGLEVEL_TRACE, "markFutureAirings: Setting DontLike for future anti-Favorite.");
                    AiringAPI.SetDontLike(airing);
                } else {
                    Log.getInstance().write(Log.LOGLEVEL_TRACE, "markFutureAirings: Not setting DontLike for future anti-Favorite.");
                }
                
                if (af.isMarkWatched()) {
                    Log.getInstance().write(Log.LOGLEVEL_TRACE, "markFutureAirings: Setting Watched for future anti-Favorite.");
                    AiringAPI.SetWatched(airing);
                } else {
                    Log.getInstance().write(Log.LOGLEVEL_TRACE, "markFutureAirings: Not setting Watched for future anti-Favorite.");
                }
            }
        }
        
        return;
    }
    
    static ArrayList<Object> getFutureAirings() {
        
        ArrayList<Object> list = new ArrayList<Object>();
        long now = Utility.Time();
        
        Vector allAirings = Database.SearchSelectedFields(" ", false, true, true, true, true, true, true, true, true, true, "T");
        
        for (Iterator it = allAirings.iterator(); it.hasNext();) {
            Object Airing = it.next();
            if (AiringAPI.GetAiringStartTime(Airing) > now)
                list.add(Airing);
        }
        
        Log.getInstance().write(Log.LOGLEVEL_TRACE, "getFutureAirings: Found " + list.size()); 
            
        return list;       
    }
    
    
}
